<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2022/6/1
 * Time: 11:30
 */

namespace plugin\admin\app\middleware;


use app\exception\IndexException;
use plugin\admin\app\exception\AdminException;
use plugin\admin\app\model\admin\AdminRole;
use plugin\admin\app\model\admin\Role;
use plugin\admin\app\model\admin\Rule;
use support\Cache;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;

class JwtToken implements MiddlewareInterface
{
    public function process(Request $request, callable $next): Response
    {
        $path = ltrim($request->path(),'\/');
        if(strpos($path,'app/admin')===0 && ($request->expectsJson()==false)){
            return $next($request);
        }

        // 通过反射获取控制器哪些方法不需要登录
        $controller = new \ReflectionClass($request->controller);
        $parentClass = $controller->getParentClass()->getName();
        $isLogin = true;
        if(strpos($parentClass,'AuthController')===false){
            $isLogin = false;
        }

        try{
            $this->getAdminInfo($request);
        }catch (\Exception $e){
            if($isLogin==true){
                throw $e;
            }
        }

        return $next($request);
    }

    private function getAdminInfo($request)
    {
        $request->token = $request->header('token');

        if(empty($request->token)){
            throw new AdminException(1000,'token does not exist');
        }

        $adminInfo = \app\common\lib\JwtToken::getInstance()->validateToken($request->token);

        if(empty($adminInfo)){
            throw new AdminException(1000,'token error');
        }

        $adminInfo = json_decode(json_encode($adminInfo), true);

        $user = Cache::get(md5($request->token));
        if(!empty($user)){
            $adminInfo = $user;
        }elseif((time()-$adminInfo['login_time'])>60){
            $adminInfo = \plugin\admin\app\model\admin\Admin::getInstance()->getWhere(['id'=>$adminInfo['id']])->first();
            if(empty($adminInfo)){
                throw new AdminException(1000,'admin does not exist');
            }
            $adminInfo = $adminInfo->toArray();
            $adminInfo['login_time'] = time();
            Cache::set(md5($request->token),$adminInfo,60);
        }

        $adminInfo = json_decode(json_encode($adminInfo), true);
        $request->curAdminId = $adminInfo['id'];
        $request->curAdminName = $adminInfo['username'];
        $request->curAdminInfo = $this->canAccess($adminInfo,$request);

        return true;
    }

    /**
     * 判断是否有权限
     * @param $adminInfo
     * @param $request
     * @return bool
     * @throws AdminException
     */
    public  function canAccess($adminInfo,$request)
    {
        $controller = $request->controller;
        $action = $request->action;

        $adminInfo['role_ids'] = AdminRole::where('admin_id', $adminInfo['id'])->pluck('role_id')->toArray();

        // 当前管理员无角色
        $roles = $adminInfo['role_ids'];
        if (!$roles) {
            throw new AdminException(4020,'无权限');
        }

        // 角色没有规则
        $rules = Role::whereIn('id', $roles)->pluck('rules');
        $rule_ids = [];
        foreach ($rules as $rule_string) {
            if (!$rule_string) {
                continue;
            }
            $rule_ids = array_merge($rule_ids, explode(',', $rule_string));
        }
        if (!$rule_ids) {
            throw new AdminException(4020,'无权限');
        }

        // 超级管理员
        if (in_array('*', $rule_ids)){
            return $adminInfo;
        }
        if($controller=='plugin\admin\app\controller\admin\IndexController'){
            return $adminInfo;
        }
        if($controller=='plugin\admin\app\controller\IndexController'){
            return $adminInfo;
        }

        // 如果action为index，规则里有任意一个以$controller开头的权限即可
        if (strtolower($action) === 'index') {
            $rule = Rule::where(function ($query) use ($controller, $action) {
                $controller_like = str_replace('\\', '\\\\', $controller);
                $query->where('key', 'like', "$controller_like@%")->orWhere('key', $controller);
            })->whereIn('id', $rule_ids)->first();

            if (!$rule) {
                throw new AdminException(4020,'无权限');
            }
        }

        // 查询是否有当前控制器的规则
        $rule = Rule::where(function ($query) use ($controller, $action) {
            $query->where('key', "$controller@$action")->orWhere('key', $controller);
        })->whereIn('id', $rule_ids)->first();

        if (!$rule) {
            throw new AdminException(4020,'无权限');
        }

        return $adminInfo;
    }

}
